home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / DTS.StyleChat / Window.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-18  |  31.4 KB  |  1,048 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        Window.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1990-1993 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* You may incorporate this sample code into your applications without
  12. ** restriction, though the sample code has been provided "AS IS" and the
  13. ** responsibility for its operation is 100% yours.  However, what you are
  14. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  15. ** after having made changes. If you're going to re-distribute the source,
  16. ** we require that you make it clear in the source that the code was
  17. ** descended from Apple Sample Code, but that you've made changes. */
  18.  
  19. /* This file contains the code for the document procedure pointers for the main Wannabe
  20. ** document.  Wannabe currently only supports one type of documents, type 'DUMD',
  21. ** which stands for "DUMb Document". */
  22.  
  23. /* For more information on this file, please read the read.me file "=How to write your app". */ 
  24.  
  25.  
  26.  
  27. /*****************************************************************************/
  28.  
  29.  
  30.  
  31. #include "App.h"            /* Get the application includes/typedefs, etc.    */
  32. #include "App.defs.h"        /* Get various application definitions.            */
  33. #include "App.protos.h"        /* Get the prototypes for application.            */
  34.  
  35. #ifndef __ERRORS__
  36. #include <Errors.h>
  37. #endif
  38.  
  39. #ifndef __FONTS__
  40. #include <Fonts.h>
  41. #endif
  42.  
  43. #ifndef __RESOURCES__
  44. #include <Resources.h>
  45. #endif
  46.  
  47. #ifndef __TOOLUTILS__
  48. #include <ToolUtils.h>
  49. #endif
  50.  
  51. #ifndef __UTILITIES__
  52. #include "Utilities.h"
  53. #endif
  54.  
  55.  
  56.  
  57. /*****************************************************************************/
  58.  
  59.  
  60.  
  61. Boolean        gNoDefaultDocument = false;
  62.                     /* Set to true if app should boot with no default document. */
  63.                     /* This tells DTS.Lib..framework what you want. */
  64.  
  65. OSType        gAppWindowType = kDocFileType;    /* Main document type. */
  66. long        gAppWindowAttr = kwAppWindow;    /* Main window attributes. */
  67.  
  68. short        gMinVersion    = kMinVersion;    /* Minimum document version app can support. */
  69. short        gMaxVersion    = kMaxVersion;    /* Maximum document version app can support. */
  70.                                             /* More informing DTS.Lib..framework. */
  71.  
  72. extern Boolean        gStartingUp;
  73.  
  74. extern short        gPrintPage;                /* Non-zero means we are printing. */
  75.                                             /* DTS.Lib..framework global. */
  76.  
  77. extern RgnHandle    gCursorRgn;                /* We handle cursors here, so we need */
  78. extern CursPtr        gCursorPtr;                /* to know about these things. */
  79.                                             /* Above are DTS.Lib..framework globals. */
  80.  
  81. /* Currently Wannabe doesn't ever change the cursor, so we don't actually need
  82. ** these referenced here.  However, since Wannabe is supposed to be an application in
  83. ** progress, it is very likely that you will need to reference these as your project
  84. ** develops.  See DTS.StyleChat and DTS.Draw for examples of setting the cursor. */
  85.  
  86. /* Some cursors are pointer-based, and some cursors are resource-based.
  87. ** If a cursor is resource-based, it needs to be loaded and made to not move,
  88. ** and then gCursorPtr can be set to point to it.  This makes all cursors
  89. ** pointer-based.  Also, gCursorPtr is used by DTS.Lib..framework to
  90. ** determine if there is a current cursor.  If gCursorPtr is nil, then
  91. ** there is no current cursor, and the cursor has to be recalculated, no
  92. ** matter where the mouse is.  If gCursorPtr is not nil, then if the
  93. ** mouse position is within the cursor region gCursorRgn, the cursor is
  94. ** correct, and no recalculation is necessary.  If it is outside this region,
  95. ** then it is recalculated.  What does this all mean?  It means that if you
  96. ** want to guarantee that the cursor is recalculated next time DoWindowCursor()
  97. ** is called, set gCursorPtr to nil.
  98. **
  99. ** If you have a cursor resource, you need to:
  100. ** 1) Load the resource.
  101. ** 2) Make a fixed copy of it.
  102. ** 3) Set the cursor to it.
  103. ** 4) Set gCursorPtr to point to the fixed copy.
  104. **
  105. ** There is a function that does almost all of this, called DoSetResCursor().
  106. ** It does all but set gCursorPtr to it.  (It actually sets gCursorPtr to nil.)
  107. ** It does return a pointer to the permanent copy, so typically what you will
  108. ** want to do is the following:
  109. **     gCursorPtr = DoSetResCursor(theCursorID);
  110. **
  111. ** So why set gCursorPtr to nil as the default action?  This allows you to
  112. ** set a temporary cursor, which will be replaced when DoWindowCursor() is
  113. ** called next, or it allows you to set a cursor that maps to the cursor
  114. ** region gCursorRgn (by setting gCursorPtr to the return result). */
  115.  
  116. static Boolean    GoFast(TEHandle teHndl, EventRecord *event);
  117.  
  118.  
  119.  
  120. /*****************************************************************************/
  121. /*****************************************************************************/
  122.  
  123.  
  124.  
  125. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  126.  
  127. /* Calculate application specific frame area (Called by DoCalcFrameRgn).
  128. ** You are passed an empty region.  You are supposed to add any custom frame
  129. ** parts that this document uses.  Typically there are no frame portions, as
  130. ** they are accounted for in other ways.  The scrollbars and grow icon will
  131. ** automatically be contributed to the calculation of the frame region.
  132. ** If you use sidebars, these are also added in automatically.  This is only
  133. ** used if the frame region is more complicated than can automatically be
  134. ** handled.  So, almost always, you will simply leave the region empty. */
  135.  
  136. #pragma segment TheDoc
  137. void    CalcFrameRgn(FileRecHndl frHndl, WindowPtr window, RgnHandle rgn)
  138. {
  139. #ifndef __MWERKS__
  140. #pragma unused (frHndl, window, rgn)
  141. #endif
  142. }
  143.  
  144.  
  145.  
  146. /*****************************************************************************/
  147.  
  148.  
  149.  
  150. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  151.  
  152. /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
  153. ** a window.  Other applications might want to call FindControl, TEClick, etc., to
  154. ** further process the click. */
  155.  
  156. #pragma segment TheDoc
  157. void    ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
  158. {
  159. #ifndef __MWERKS__
  160. #pragma unused (firstClick)
  161. #endif
  162.  
  163.     ControlHandle    ctl;
  164.     short            action, cnum;
  165.     FileRecHndl        frHndl;
  166.  
  167.     cnum = IsCtlEvent(window, event, &ctl, &action);
  168.         /* That was easy.  Scrolling was just handled.  Other stuff would be handled
  169.         ** by IsCtlEvent, if we had other stuff to do.  We don't have any other
  170.         ** controls in the content besides the document scrollbars. */
  171.  
  172.     frHndl = (FileRecHndl)GetWRefCon(window);
  173.     switch (cnum) {
  174.         case 1000:
  175.             SendMessage(frHndl, kStylMssg);
  176.             SendMessage(frHndl, kTextMssg);
  177.             break;
  178.         case 1010:
  179.             AllowAutoReconnect(frHndl);
  180.             SendConnect(frHndl, (char *)"\pDTS.Chat");
  181.             SetWindowDirty(window);
  182.             break;
  183.         case 1020:
  184.             if ((*frHndl)->connect.connected) {
  185.                 SendMessage(frHndl, kDisconnectMssg);
  186.                 (*frHndl)->connect.remotePath[0] = 0;
  187.             }
  188.             CNum2Ctl(window, 1020, &ctl);
  189.             (*ctl)->contrlVis = false;
  190.             BeginFrame(window);
  191.             CNum2Ctl(window, 1010, &ctl);
  192.             ShowStyledControl(ctl);
  193.             CNum2Ctl(window, 1000, &ctl);
  194.             (*ctl)->contrlVis = false;
  195.             CNum2Ctl(window, 1002, &ctl);
  196.             DoDraw1Control(ctl, false);
  197.             EndFrame(window);
  198.             break;
  199.     }
  200.  
  201.     return;
  202. }
  203.  
  204.  
  205.  
  206. /*****************************************************************************/
  207.  
  208.  
  209.  
  210. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  211.  
  212. /* DoKeyDown() is first called by the application.  Then if the key isn't a menu
  213. ** key, DoKeyDown() calls this code.  Here are the rules for this function:
  214. **
  215. ** 1) If you handle the key, return(true).  This completes the key handling.
  216. ** 2) If you don't handle the key, you return false.  However, there are two
  217. **    situations for not handling the key:
  218. **      a) You want someone else to.
  219. **      b) You want nobody else to look at the key.
  220. **    This is what the boolean passThrough is for.  If you wish the next window
  221. **    to have a look at the key, set the boolean passThrough to true.  passThrough
  222. **    is already initialized to false, which is the common case, so you only have
  223. **    to worry about setting it true.
  224. **
  225. ** If you have a window that never processes keys and always passes them through,
  226. ** just set the contentKeyProc to nil.  This will indicate to the application
  227. ** framework that all keys should be passed through this window.  DTS.Draw has
  228. ** such a window.  Its palette window doesn't accept keys.  They are passed through
  229. ** to document windows. */
  230.  
  231. #pragma segment TheDoc
  232. Boolean    ContentKey(WindowPtr window, EventRecord *event, Boolean *passThrough)
  233. {
  234. #ifndef __MWERKS__
  235. #pragma unused (passThrough)
  236. #endif
  237.  
  238.     short        cnum, action;
  239.     FileRecHndl        frHndl;
  240.  
  241.     cnum = IsCtlEvent(window, event, nil, &action);
  242.  
  243.     frHndl = (FileRecHndl)GetWRefCon(window);
  244.     switch (cnum) {
  245.         case 101:
  246.             if (action == 2) {
  247.                 SetWindowDirty(window);
  248.                 DoAdjustMenus();
  249.                 return(true);
  250.             }
  251.             break;
  252.         case 1000:
  253.             SendMessage(frHndl, kStylMssg);
  254.             SendMessage(frHndl, kTextMssg);
  255.             return(true);
  256.             break;
  257.     }
  258.  
  259.     return(false);
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************/
  265.  
  266.  
  267.  
  268. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  269.  
  270. /* Draw application specific content (Called by DoDrawFrame).
  271. **
  272. ** If your application has any custom frame areas, or if it uses sidebars,
  273. ** this is the function that you would put the frame drawing code.  The
  274. ** document scrollbars and grow icon drawing is handled by DTS.framework.
  275. ** Just do the sidebar and custom areas here. */
  276.  
  277. #pragma segment TheDoc
  278. void    DrawFrame(FileRecHndl frHndl, WindowPtr window, Boolean activate)
  279. {
  280.     MoveTo(0, (*frHndl)->fileState.topSidebar - 1);
  281.     LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, (*frHndl)->fileState.topSidebar - 1);
  282.     LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, 16383);
  283.  
  284.     BeginFrame(window);
  285.     DoDrawControls(window, activate);
  286.     EndFrame(window);
  287. }
  288.  
  289.  
  290.  
  291. /*****************************************************************************/
  292.  
  293.  
  294.  
  295. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  296.  
  297. /* Frees up any application-specific memory in the document.  This is called by
  298. ** DoFreeDocument, which is called by DisposeDocument().  The application would
  299. ** call DisposeDocument(), not DoFreeDocument() or FreeDocument() directly.
  300. **
  301. ** The document may have a bunch of handles off the main handle of the document.
  302. ** This is where they are freed.  DisposeDocument calls this prior to releasing
  303. ** the ram for the main handle of the document, so release everything else
  304. ** here, or you will have a memory leak.
  305. **
  306. ** NOTE:  Calling DefaultFreeDocument() frees up all memory used by a
  307. ** hierarchical document (see TreeObj package). */
  308.  
  309. #pragma segment TheDoc
  310. OSErr    FreeDocument(FileRecHndl frHndl)
  311. {
  312.     Handle            textHndl;
  313.     StScrpHandle    textStyl;
  314.  
  315.     textHndl = (*frHndl)->d.doc.textHndl;
  316.     if (textHndl) {
  317.         DisposeHandle(textHndl);
  318.         (*frHndl)->d.doc.textHndl = nil;
  319.     }
  320.     textStyl = (*frHndl)->d.doc.textStyl;
  321.     if (textStyl) {
  322.         DisposeHandle((Handle)textStyl);
  323.         (*frHndl)->d.doc.textStyl = nil;
  324.     }
  325.     DefaultFreeDocument(frHndl);
  326.  
  327.     return(noErr);
  328. }
  329.  
  330.  
  331.  
  332. /*****************************************************************************/
  333.  
  334.  
  335.  
  336. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  337.  
  338. /* Any additional window disposal tasks can be handled here. */
  339.  
  340. #pragma segment TheDoc
  341. OSErr    FreeWindow(FileRecHndl frHndl, WindowPtr window)
  342. {
  343. #ifndef __MWERKS__
  344. #pragma unused (window)
  345. #endif
  346.  
  347.     WindowPtr    ww;
  348.     FileRecHndl    ff;
  349.  
  350.     SendMessage(frHndl, kDisconnectMssg);
  351.         /* Let the remote user know the window is closing.  We must handle this,
  352.         ** as DTS.Lib..framework doesn't.   it is application-specific. */
  353.  
  354.     if ((*frHndl)->fileState.sfType == kDocFileType) {
  355.         for (ww = nil; (ww = GetNextWindow(ww, 0)) != nil;) {
  356.             ff = (FileRecHndl)GetWRefCon(ww);
  357.             if ((*ff)->fileState.sfType == kViewHierFileType) {
  358.                 if ((*frHndl)->d.doc.root == (*ff)->d.doc.root) {
  359.                     DisposeOneWindow(ww, kClose);
  360.                     ww = nil;
  361.                 }
  362.             }
  363.         }
  364.     }
  365.  
  366.     return(noErr);
  367.         /* We always return noErr here, even if SendMessage returned an error.  Why?
  368.         ** Because we don't want the closing of the window to halt just because the
  369.         ** network connection may have been lost, which is about the only error that
  370.         ** can occur.  If there's something bogus about the window, we most likely
  371.         ** want to get rid of it, with good riddance. */
  372. }
  373.  
  374.  
  375.  
  376. /*****************************************************************************/
  377.  
  378.  
  379.  
  380. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  381.  
  382. /* Image the document into the current port.
  383. **
  384. ** The only thing tricky about this function is that it needs to key off of
  385. ** the global variable gPrintPage.  gPrintPage is the current page that is
  386. ** being printed.  If gPrintPage is 0, then you are drawing to the window.
  387. **
  388. ** For when printing:
  389. **
  390. ** If gPrintPage is non-0, that is the page to be printed.  If after imaging
  391. ** the page there are no more pages, you should set gPrintPage to 0.  This
  392. ** indicates to the print loop that the end of the document has been reached.
  393. ** Even if the user indicated in the job dialog to print more pages, setting
  394. ** gPrintPage to 0 states that the last page has been printed.  This is necessary
  395. ** because the print loop can't know when printing is done.  The imaging procedure
  396. ** is the logical one to state when everything has been imaged. */
  397.  
  398. #pragma segment TheDoc
  399. OSErr    ImageDocument(FileRecHndl frHndl)
  400. {
  401.     WindowPtr        thePort;
  402.     Rect            rct, theInk;
  403.     TEHandle        te;
  404.     short            pageCol;
  405.     OSErr            err;
  406.     static short    taskOffset, taskNum;
  407.  
  408.     err = noErr;
  409.     GetPort(&thePort);
  410.  
  411.     if (!gPrintPage) {                                        /* If not printing... */
  412.         DoDrawControls(thePort, false);                        /* Draw the content controls. */
  413.     }
  414.     else {
  415.  
  416.         if (gPrintPage == 1)
  417.             taskOffset = taskNum = 0;
  418.  
  419.         theInk = thePort->portRect;
  420.         InsetRect(&theInk, 4, 4);        /* Just so no characters get clipped. */
  421.  
  422.         pageCol = 0;
  423.         for (rct = theInk; taskNum < 2;) {
  424.             te  = (taskNum) ? (*frHndl)->d.doc.outBox : (*frHndl)->d.doc.inBox;
  425.             err = CTEPrint(te, &taskOffset, &rct);
  426.             if (err) break;
  427.             if (taskOffset != -1) return(noErr);    /* Text went to bottom of page. */
  428.             taskOffset = 0;                            /* Done with this TextEdit record. */
  429.             ++taskNum;
  430.             rct.top    = rct.bottom + 20;
  431.             rct.bottom = theInk.bottom;
  432.             if (rct.top + 20 >= rct.bottom) return(noErr);
  433.                 /* No page left or not enough to bother with. */
  434.         }
  435.         gPrintPage = 0;
  436.     }
  437.  
  438.     return(err);
  439. }
  440.  
  441.  
  442.  
  443. /*****************************************************************************/
  444.  
  445.  
  446.  
  447. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  448.  
  449. /* This function does the remaining window initialization.
  450. **
  451. ** There may be additional content initialization for the window.  At this point,
  452. ** you have a window, but it is currently invisible.  If you return noErr, then
  453. ** the window will be set to the state indicated for that window.  Why this function?
  454. ** You may wish to add controls to the content of the window.  You may have a
  455. ** TextEdit record in the content.  All of these sort of things can't be created
  456. ** until there is a window to contain them.  First a document is read in, and then
  457. ** if the document creation succeeds, a window is created for that document.
  458. ** At this point we have a document, and we are on our way to having a window.
  459. ** All that remains is any additional content initialization.  Do it, return
  460. ** noErr, and everybody's happy.  If something goes wrong here, return the error,
  461. ** and the incomplete window will be disposed of. */
  462.  
  463. #pragma segment TheDoc
  464. OSErr    InitContent(FileRecHndl frHndl, WindowPtr window)
  465. {
  466.     OSErr            err;
  467.     WindowPtr        oldPort;
  468.     ControlHandle    ctl;
  469.     TEHandle        te;
  470.     Handle            text;
  471.     StScrpHandle    styl;
  472.  
  473.     err = AddControlSet(window, (*frHndl)->fileState.sfType, kwStandardVis, 0, 0, nil);
  474.     if (err) return(err);
  475.  
  476.     GetPort(&oldPort);
  477.     SetPort(window);
  478.  
  479.     CNum2Ctl(window, 100, &ctl);
  480.     (*frHndl)->d.doc.inBox = (TEHandle)GetControlReference(ctl);
  481.  
  482.     CNum2Ctl(window, 101, &ctl);
  483.     (*frHndl)->d.doc.outBox = te = (TEHandle)GetControlReference(ctl);
  484.     CTESetFastKeys(te, GoFast);
  485.  
  486.     text = (*frHndl)->d.doc.textHndl;
  487.     if (text) {
  488.         styl = (*frHndl)->d.doc.textStyl;
  489.         DisposeHandle(CTESwapText(te, text, styl, false));
  490.         (*frHndl)->d.doc.textHndl = nil;
  491.         if (styl) {
  492.             DisposeHandle((Handle)styl);
  493.             (*frHndl)->d.doc.textStyl = nil;
  494.         }
  495.     }
  496.  
  497.     ResizeContent(window, 0, 0);
  498.  
  499.     if (!(*frHndl)->connect.connected) {
  500.         if (!(*frHndl)->connect.remoteLoc.dataHandle) {
  501.             CNum2Ctl(window, 1010, &ctl);
  502.             (*ctl)->contrlVis = 0xFF;
  503.         }
  504.     }
  505.  
  506.     SetDocSize(frHndl, kwNoChange, 4096);
  507.  
  508.     SetPort(oldPort);
  509.     return(noErr);
  510. }
  511.  
  512. static Boolean    GoFast(TEHandle teHndl, EventRecord *event)
  513. {
  514. #ifndef __MWERKS__
  515. #pragma unused (teHndl)
  516. #endif
  517.  
  518.     if (event->modifiers & cmdKey) return(false);
  519.     return(true);
  520. }
  521.  
  522.  
  523.  
  524. /*****************************************************************************/
  525.  
  526.  
  527.  
  528. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  529.  
  530. #pragma segment TheDoc
  531. OSErr    ReadDocument(FileRecHndl frHndl)
  532. {
  533.     short            fileRefNum, oldRes;
  534.     OSErr            err;
  535.     char            hstate;
  536.     long            count;
  537.     Handle            textHndl;
  538.     StScrpHandle    styl;
  539.     ConnectRec        **ach;
  540.     AEAddressDesc    remoteLoc;
  541.     long            timeout;
  542.  
  543.     fileRefNum = (*frHndl)->fileState.refNum;
  544.  
  545.     err = SetFPos(fileRefNum, fsFromStart, 0);
  546.         /* Set the file position to the beginning of the file. */
  547.  
  548.     if (!err)
  549.         err = DoReadDocumentHeader(frHndl);
  550.             /* Read the document header.
  551.             ** Note that this doesn't guarantee that we will actually do something.
  552.             ** Text documents don't have a header.  The read and write header procs have
  553.             ** been set to nil for text documents, so calling DoReadDocumentHeader
  554.             ** will do nothing for text documents.  DTS.StyleChat documents do have a header,
  555.             ** and by calling DoReadDocumentHeader, the header will be read in. */
  556.  
  557.     if (err == resNotFound) err = noErr;
  558.  
  559.     if (!err) {        /* Read TextEdit text from file. */
  560.         textHndl = NewHandle(kMaxNumChars);
  561.         if (!(err = MemError())) {
  562.             count = kMaxNumChars;
  563.                 /* The size of the text isn't saved to disk.  This is the maximum
  564.                 ** that a TextEdit record can accept. */
  565.             hstate = LockHandleHigh(textHndl);
  566.             err    = FSRead(fileRefNum, &count, *textHndl);
  567.             HSetState(textHndl, hstate);
  568.  
  569.             if (err == eofErr)
  570.                 err = noErr;
  571.  
  572.             if (err)
  573.                 count = 0;
  574.  
  575.             SetHandleSize(textHndl, count);
  576.                 /* Set the handle to the actual size of the text on disk. */
  577.             (*frHndl)->d.doc.textHndl = textHndl;
  578.         }
  579.     }
  580.  
  581.     if (!err) {
  582.         err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
  583.         if (!err) {
  584.             styl = (StScrpHandle)GetResource(kStylResType, kStylResID);
  585.             if (styl)
  586.                 DetachResource((Handle)styl);
  587.             (*frHndl)->d.doc.textStyl = styl;
  588.         }
  589.         UseResFile(oldRes);
  590.     }
  591.  
  592.     if (!err) {
  593.         err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
  594.         if (!err) {
  595.             ach = (ConnectRec **)GetResource(kAutoConnectResType, kAutoConnectResID);
  596.             if (ach) {
  597.                 BlockMove(*ach, &(*frHndl)->connect, sizeof(ConnectRec));
  598.                 (*frHndl)->connect.connected            = false;
  599.                 (*frHndl)->connect.remoteLoc.dataHandle = nil;
  600.                 DetachResource((Handle)ach);
  601.                 DisposeHandle((Handle)ach);
  602.                 if ((*frHndl)->connect.remoteMachine[0]) {
  603.                     LaunchRemoteApp(frHndl);
  604.                     for (timeout = TickCount() + 600; timeout > TickCount();) {
  605.                         err = GetRemoteProcessTarget(frHndl, &remoteLoc, AEPortFilter);
  606.                         if (err) break;
  607.                         if (remoteLoc.dataHandle) {
  608.                             (*frHndl)->connect.remoteLoc = remoteLoc;
  609.                             SendConnect(frHndl, (char *)"\pDTS.Chat");
  610.                             break;
  611.                         }
  612.                     }
  613.                 }
  614.             }
  615.         }
  616.         UseResFile(oldRes);
  617.     }
  618.  
  619.     return(err);
  620. }
  621.  
  622.  
  623.  
  624. /*****************************************************************************/
  625.  
  626.  
  627.  
  628. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  629.  
  630. /* Resize application specific content (Called by ResizeWindow).
  631. **
  632. ** This gets called when a user does a zoom or window resizing operation.
  633. ** It is possible that things in the content need to be resized in conjunction
  634. ** with the resizing of the window. */
  635.  
  636. #pragma segment TheDoc
  637. void    ResizeContent(WindowPtr window, short oldh, short oldv)
  638. {
  639. #ifndef __MWERKS__
  640. #pragma unused (oldh, oldv)
  641. #endif
  642.  
  643.     FileRecHndl    frHndl;
  644.     WindowPtr    oldPort;
  645.     short        i;
  646.     Rect        crct, rct;
  647.     TEHandle    te;
  648.  
  649.     if (!window) return;
  650.  
  651.     frHndl  = (FileRecHndl)GetWRefCon(window);
  652.     oldPort = SetFilePort(frHndl);
  653.  
  654.     GetContentRect(window, &crct);
  655.     OffsetRect(&crct, -crct.left, -crct.top);
  656.     for (i = 0; i < 2; ++i) {
  657.         rct = crct;
  658.         --rct.top;
  659.         --rct.left;
  660.         rct.right  -= 14;
  661.  
  662.         rct.bottom = rct.top + (rct.bottom - rct.top + 1) / 2;
  663.         if (i) {
  664.             rct.top = rct.bottom - 1;
  665.             rct.bottom = crct.bottom + 1;
  666.         }
  667.  
  668.         te = (i) ? (*frHndl)->d.doc.outBox : (*frHndl)->d.doc.inBox;
  669.         CTEMove(te, rct.left, rct.top);
  670.         CTESize(te, rct.right - rct.left, rct.bottom - rct.top, true);
  671.     }
  672.  
  673.     SetPort(oldPort);
  674. }
  675.  
  676.  
  677.  
  678. /*****************************************************************************/
  679.  
  680.  
  681.  
  682. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  683.  
  684. /* Scroll application specific frame (Called by DoScrollFrame).
  685. **
  686. ** Some applications may need to scroll the "frame" of the document along
  687. ** with the document contents.  This is common for applications with rulers,
  688. ** or other similar sidebar items. */
  689.  
  690. #pragma segment TheDoc
  691. void    ScrollFrame(FileRecHndl frHndl, WindowPtr window, long dh, long dv)
  692. {
  693. #ifndef __MWERKS__
  694. #pragma unused (frHndl, window, dh, dv)
  695. #endif
  696. }
  697.  
  698.  
  699.  
  700. /*****************************************************************************/
  701.  
  702.  
  703.  
  704. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  705.  
  706. /* Since the hierarchical document package isn't used by DTS.StyleChat,
  707. ** this function actually never gets called. */
  708.  
  709. #pragma segment TheDoc
  710. void    UndoFixup(FileRecHndl frHndl, Point contOrg, Boolean afterUndo)
  711. {
  712. #ifndef __MWERKS__
  713. #pragma unused (frHndl, contOrg, afterUndo)
  714. #endif
  715.  
  716.     /* See DTS.Draw for an example of what you might do here. */
  717. }
  718.  
  719.  
  720.  
  721. /*****************************************************************************/
  722.  
  723.  
  724.  
  725. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  726.  
  727. /* This function is where you adjust the cursor to reflect the location in the
  728. ** document or window.  You have the additional input of gCursorRgn to deal
  729. ** with.  The way that the cursor handling works is as follows:
  730. ** 1) The application calls DoWindowCursor().
  731. ** 2) DoWindowCursor() works its way through the windows/documents, front to back.
  732. **    It looks at the document's windowCursorProc and checks to see if the document
  733. **    has one.  If the document doesn't have one, then it assumes that that window
  734. **    always wants an arrow.  If the cursor is over that window, the cursor is set
  735. **    to an arrow, and we're done.  If the cursor isn't over the window, then the next
  736. **    window is tried.  If all documents don't have a windowCursorProc, then the cursor
  737. **    is set to an arrow (for the non-document area of the screen).
  738. ** 3) If a document has a windowCursorProc, then the proc is called.  The proc's
  739. **    job is as follows:
  740. **    a) If the cursor is over a position that is determined by the window, then
  741. **       the proc removes other areas from gCursorRgn.  Note that it should not
  742. **       simply set the area to what it "thinks" is the correct area.  This window
  743. **       may not be the front-most.  Other windows will have already been subtracted
  744. **       from gCursorRgn.  The resultant gCursorRgn is the correct cursor area,
  745. **       and should be passed to WaitNextEvent calls in the application (already the case
  746. **       in EventLoop.c).  Also, the cursor should be set to the correct cursor, of course.
  747. **       You should also return true, as the cursor has been determined.
  748. **    b) If the cursor is not over a position for this window, then you should
  749. **       return.  You will either pass back true or false.  If you don't wish
  750. **       windows behind this window to have a shot at cursor determination, then
  751. **       return true.  This states that the cursor is "determined".  It is, in the
  752. **       sense that no further determination will occur.  If you return false, then
  753. **       other windows get a shot at determining the cursor.
  754. **
  755. ** Setting the cursor to the correct cursor isn't as easy as you would expect.
  756. ** DTS.Lib..framework uses the global gCursorPtr as the reference to the cursor.  This is
  757. ** fine if the cursor is pointer-based, but if the cursor is resource-based, it is a bit
  758. ** more of a problem.  What you will need to do is to call DoSetResCursor() to make the
  759. ** resource cursor pointer-based.  DoSetResCursor() will set gCursorPtr to nil, and it
  760. ** also returns the pointer to the permanent copy of the cursor resource.  Just set gCursorPtr
  761. ** to the return result of DoSetResCursor(), and you will be set. */
  762.  
  763. #pragma segment TheDoc
  764. Boolean    WindowCursor(FileRecHndl frHndl, WindowPtr window, Point globalPt)
  765. {
  766.     WindowPtr        oldPort;
  767.     RgnHandle        contRgn;
  768.     Rect            outBoxRct, teViewRct, contRct;
  769.     TEHandle        outBox, teHndl;
  770.     ControlHandle    viewCtl;
  771.     Point            contOrg;
  772.  
  773.     /* For the DTS.StyleChat sample, we display an i-beam cursor when over the outbox. */
  774.  
  775.     if (!window) {
  776.         SetCursor(gCursorPtr = &qd.arrow);
  777.         return(true);
  778.     }
  779.  
  780.     oldPort = SetFilePort(frHndl);
  781.     GetContentOrigin((window = (*frHndl)->fileState.window), &contOrg);
  782.     SetOrigin(contOrg.h, contOrg.v);        /* Scroll position of window. */
  783.  
  784.     viewCtl   = CTEViewFromTE(outBox = (*frHndl)->d.doc.outBox);
  785.     outBoxRct = (*viewCtl)->contrlRect;        /* Local coordinates of outbox. */
  786.     InsetRect(&outBoxRct, 2, 2);
  787.  
  788.     GetContentRect(window, &contRct);
  789.         /* This returns the content portion of the window in local coordinates,
  790.         ** less document scrollbar and sidebar areas. */
  791.  
  792.     SectRect(&outBoxRct, &contRct, &outBoxRct);
  793.         /* Part of the outbox still visible after scrolling. */
  794.  
  795.     LocalToGlobalRect(&outBoxRct);        /* The outbox rect, in global coordinates. */
  796.  
  797.     SetPort(oldPort);                    /* Put the port back. */
  798.  
  799.     CopyRgn(((WindowPeek)window)->contRgn, (contRgn = NewRgn()));
  800.  
  801.     if (CTETargetInfo(&teHndl, &teViewRct) == window) {
  802.         /* If target TextEdit control belongs to this window... */
  803.  
  804.         if ((teHndl == outBox) && (PtInRect(globalPt, &outBoxRct))) {
  805.             /* If target TextEdit control is the outbox, and the cursor
  806.             ** is over the visible part of the outbox... */
  807.  
  808.             gCursorPtr = DoSetResCursor(ibeamCursor);
  809.             RectRgn(contRgn, &outBoxRct);
  810.             SectRgn(gCursorRgn, contRgn, gCursorRgn);
  811.             DisposeRgn(contRgn);
  812.             return(true);
  813.         }
  814.     }
  815.  
  816.     return(false);
  817. }
  818.  
  819.  
  820.  
  821. /*****************************************************************************/
  822.  
  823.  
  824.  
  825. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  826.  
  827. /* After the DTS.Lib framework disposes of a window, it calls here.  This is
  828. ** to give the application a chance to do any additional tasks related to
  829. ** a window closing.  DTS.StyleChat doesn't have anything else extra to do. */
  830.  
  831. #pragma segment TheDoc
  832. void    WindowGoneFixup(WindowPtr window)
  833. {
  834. #ifndef __MWERKS__
  835. #pragma unused (window)
  836. #endif
  837. }
  838.  
  839.  
  840.  
  841. /*****************************************************************************/
  842.  
  843.  
  844.  
  845. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  846.  
  847. /* The reverse function of ReadDocument. */
  848.  
  849. #pragma segment TheDoc
  850. OSErr    WriteDocument(FileRecHndl frHndl)
  851. {
  852.     short            fileRefNum, oldRes;
  853.     OSErr            err;
  854.     char            hstate;
  855.     long            count, fpos;
  856.     TEHandle        te;
  857.     Handle            textHndl, oldr, ach;
  858.     StScrpHandle    styl;
  859.     ConnectRec        ac;
  860.  
  861.     fileRefNum = (*frHndl)->fileState.refNum;
  862.  
  863.     err = SetFPos(fileRefNum, fsFromStart, 0);
  864.         /* Set the file position to the beginning of the file. */
  865.  
  866.     if (!err)
  867.         err = DoWriteDocumentHeader(frHndl);
  868.             /* Write the document header.
  869.             ** Note that this doesn't guarantee that we will actually do something.
  870.             ** Text documents don't have a header.  The read and write header procs have
  871.             ** been set to nil for text documents, so calling DoWriteDocumentHeader
  872.             ** will do nothing for text documents.  DTS.StyleChat documents do have a header,
  873.             ** and by calling DoWriteDocumentHeader, the header will be written out. */
  874.  
  875.     if (!err) {        /* Write out-box TextEdit control text to file. */
  876.         te       = (*frHndl)->d.doc.outBox;
  877.         textHndl = (*te)->hText;
  878.         count    = (*te)->teLength;
  879.         hstate   = LockHandleHigh(textHndl);
  880.         err      = FSWrite(fileRefNum, &count, *textHndl);
  881.         HSetState(textHndl, hstate);
  882.     }
  883.  
  884.     if (!err) {
  885.         err = GetFPos(fileRefNum, &fpos);
  886.         if (!err)
  887.             err = SetEOF(fileRefNum, fpos);
  888.     }            /* The document may be shorter than last time it was written to disk.
  889.                 ** Handle this case by ending the file based on the new length. */
  890.  
  891.     if (!err) {
  892.         styl = CTEGetFullStylScrap((*frHndl)->d.doc.outBox);
  893.         if (styl) {
  894.             err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
  895.             if (!err) {
  896.                 oldr = GetResource(kStylResType, kStylResID);
  897.                 if (oldr) RemoveResource(oldr);
  898.                 AddResource((Handle)styl, kStylResType, kStylResID, nil);
  899.                 WriteResource((Handle)styl);
  900.                 DetachResource((Handle)styl);
  901.                 DisposeHandle((Handle)styl);
  902.             }
  903.             UseResFile(oldRes);
  904.         }
  905.     }
  906.  
  907.     if (!err) {
  908.         err = UseDocResFile(frHndl, &oldRes, fsRdWrPerm);
  909.         if (!err) {
  910.             oldr = GetResource(kAutoConnectResType, kAutoConnectResID);
  911.             if (oldr) RemoveResource(oldr);
  912.             ac = (*frHndl)->connect;
  913.             if (ac.remotePath[0]) {
  914.                 ach = NewHandle(sizeof(ConnectRec));
  915.                 if (ach) {
  916.                     BlockMove(&ac, *ach, sizeof(ConnectRec));
  917.                     AddResource(ach, kAutoConnectResType, kAutoConnectResID, nil);
  918.                     WriteResource(ach);
  919.                     DetachResource(ach);
  920.                     DisposeHandle(ach);
  921.                 }
  922.             }
  923.         }
  924.         UseResFile(oldRes);
  925.     }
  926.  
  927.     return(err);
  928. }
  929.  
  930.  
  931.  
  932. /*****************************************************************************/
  933.  
  934.  
  935.  
  936. /* •• You don't call this.  DTS.Lib..framework does at open-application time. •• */
  937.  
  938. #pragma segment TheDoc
  939. OSErr    DoOpenApplication(void)
  940. {
  941.     MenuHandle    menu;
  942.  
  943.     gStartingUp = true;
  944.  
  945.     menu = GetMenuHandle(mFonts);
  946.     if (menu)
  947.         AppendResMenu(menu, 'FONT');
  948.  
  949.     return(noErr);
  950. }
  951.  
  952.  
  953.  
  954. /*****************************************************************************/
  955. /*****************************************************************************/
  956. /*****************************************************************************/
  957.  
  958.  
  959.  
  960. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  961.  
  962. #pragma segment TheDoc
  963. Boolean    AdjustMenuItems(WindowPtr window, short menuID)
  964. {
  965.     Boolean        redrawMenuBar;
  966.     MenuHandle    menu;
  967.  
  968.     redrawMenuBar = false;
  969.  
  970.     switch (menuID) {
  971.         case mFile:
  972.             redrawMenuBar = DoAdjustFileMenu(window);
  973.             break;
  974.         case mEdit:
  975.             redrawMenuBar = DoAdjustEditMenu(window);
  976.             break;
  977.         case mFonts:
  978.             redrawMenuBar = DoAdjustFontsMenu(window);
  979.             break;
  980.         default:
  981.             menu = GetMenuHandle(menuID);
  982.             if (menu)
  983.                 (*menu)->enableFlags |= 0xFFFFFFFEL;
  984.             break;
  985.     }
  986.  
  987.     return(redrawMenuBar);
  988. }
  989.  
  990.  
  991.  
  992. /*****************************************************************************/
  993.  
  994.  
  995.  
  996. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  997.  
  998. #pragma segment TheDoc
  999. Boolean    DoMenuItem(WindowPtr window, short menuID, short menuItem)
  1000. {
  1001. #ifndef __MWERKS__
  1002. #pragma unused (window)
  1003. #endif
  1004.  
  1005.     return(DoMenuCommand(menuID, menuItem));
  1006. }
  1007.  
  1008.  
  1009.  
  1010. /*****************************************************************************/
  1011. /*****************************************************************************/
  1012. /*****************************************************************************/
  1013.  
  1014.  
  1015.  
  1016. #pragma segment TheDoc
  1017. OSErr    DuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
  1018. {
  1019.     OSErr        err;
  1020.     TEHandle    te;
  1021.     Handle        oldHndl, newHndl;
  1022.     long        size;
  1023.  
  1024.     err = NewDocument(newFrHndl, (*oldFrHndl)->fileState.sfType, true);
  1025.         /* Create a document and root object to copy the file data into. */
  1026.  
  1027.     if (err) return(err);
  1028.  
  1029.     te      = (*oldFrHndl)->d.doc.outBox;
  1030.     oldHndl = (*te)->hText;
  1031.     size    = (*te)->teLength;
  1032.     newHndl = NewHandle(size);
  1033.     if (newHndl) {
  1034.         (**newFrHndl)->d.doc.textHndl = newHndl;
  1035.         BlockMove(*oldHndl, *newHndl, size);
  1036.     }
  1037.     else {
  1038.         err = MemError();
  1039.         DisposeDocument(*newFrHndl);
  1040.         *newFrHndl = nil;
  1041.     }
  1042.  
  1043.     return(err);
  1044. }
  1045.  
  1046.  
  1047.  
  1048.